/* 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

Title : com.Angaliwa.StageHandler
Author : Dave Jansen -- Zenitum
URL : http://www.zenitum.com/

Description : Gives you (and Angaliwa) the power to easily
			  work with the Stage, ie. for setting event
			  listeners, add keyboard shortcuts and the 
			  like. Requires Angaliwa's DaisyChain and
			  Settings modules (or equivalent).
			  
			  Note: This class should be initialized 
			  _after_ the Stage becomes available, for
			  example by using the 'addedToStage'. Calling
			  the class before the Stage is present will
			  result in it not working.

History		: v1.0.090827 Initial version

Created 	: August 27th, 2009

Version		: 1.0
Compatibility: 1.0

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
*/

package com.Angaliwa{
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	
	public class StageHandler{
		/*
			Available daisyChain actions:
			- active
			- inactive
			- idlestart
		*/
		public var daisyChain:DaisyChain = new DaisyChain(this),
				   settings:Settings = new Settings(this);
		
		private var stage:Stage,
					keys:Array = [],
					active:Array = [],
					applicationActive:Boolean=true,
					t:Timer;
		
		public function StageHandler(stage:Stage){
			this.stage = stage;
			
			settings.setDefaults({
				showDebug:false,
				monitorKeyPresses:true,
				monitorIdleness:true,
				idleTimeoutLength: 10000
			});
			
			if(settings.get('monitorKeyPresses')){
				stage.addEventListener(KeyboardEvent.KEY_DOWN, keyEvent);
				stage.addEventListener(KeyboardEvent.KEY_UP, keyEvent);
			}
			
			if(settings.get('monitorIdleness')){
				stage.addEventListener(Event.ACTIVATE, activityEvent);
				stage.addEventListener(Event.DEACTIVATE, activityEvent);
			}
		}
		
		public function add(type:String, func:Function):StageHandler{
			stage.addEventListener(type,func);
			
			return this;
		}
		
		public function get():Stage{
			return stage;
		}
		
		public function del(type:String, func:Function=undefined):StageHandler{
			if(stage.hasEventListener(type))
				stage.removeEventListener(type,func);
			
			return this;
		}
		
		public function key(settings:Object, functionDown:Function, functionUp:Function=undefined, repeat:Boolean=false):StageHandler{
			var keySettings:Settings = new Settings();
			keySettings.setDefaults({
							charCode:0,
							keyCode:0,
							ctrlKey:false,
							altKey:false,
							shiftKey:false
						})
						.add(settings)
						.add({functionDown: functionDown,
							functionUp: functionUp,
							repeat: repeat});
			
			keys.push(keySettings);
			
			return this;
		}
		
		private function keyEvent(e:KeyboardEvent):void{
			if(settings.get('showDebug'))
				trace('KEYBOARD: '+e);
			
			keys.forEach(function(item:Settings, index:int, arr:Array):void{
				if( (item.get('keyCode') == e.keyCode || item.get('keyCode')==0)
					&& item.get('ctrlKey') == e.ctrlKey
					&& item.get('altKey') == e.altKey
					&& item.get('shiftKey') == e.shiftKey){
					
					item.add({'keyCode':e.keyCode});
					
					if(e.type == "keyDown" && active.indexOf(e.keyCode)<0 && item.get('functionDown')){
						// Make sure no item is in focus.
						// Note: Needs A LOT of work.
						stage.focus=null;
						
						if(!item.get('repeat')) active.push(e.keyCode);
						item.get('functionDown')();
					}
					else if(e.type == "keyUp"){
						active.splice(active.indexOf(e.keyCode),1);
						
						if(item.get('functionUp'))
							item.get('functionUp')();
					}
				}
				else if(e.type == "keyUp" && item.get('keyCode') == e.keyCode && active.indexOf(e.keyCode)>-1){
					active.splice(active.indexOf(e.keyCode),1);
					
					if(item.get('functionUp'))
						item.get('functionUp')();
				}
			});
		}
		
		private function activityEvent(e:Event):void{
			if(e.type == "activate"){
				if(!applicationActive){
					if(t) t.stop();
					daisyChain.run('active', stage);
				}
				applicationActive = true;
			}
			else{
				daisyChain.run('inactive', stage);
				t = new Timer(settings.get('idleTimeoutLength'), 1);
				t.addEventListener(TimerEvent.TIMER, function():void{
					applicationActive = false;
					daisyChain.run('idlestart', stage);
				});
				t.start();
			}
		}
	}
}